#ifdef _WIN32
#include "boinc_win.h"
#else
#include "config.h"
#endif

#ifndef _WIN32
#include <cstdio>
#include <cctype>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <csignal>
#include <unistd.h>
#endif


#define BOINC_APP_GRAPHICS

#ifdef BOINC_APP_GRAPHICS
#include "graphics_api.h"
#include "graphics_lib.h"
#endif

#include "diagnostics.h"
#include "util.h"
#include "filesys.h"
#include "boinc_api.h"
#include "mfile.h"
#include "windows.h"
#include "stdio.h"

#include <matrix\gsl_matrix.h>
#include <multifit\gsl_multifit.h>
#include <test\gsl_test.h>
#include <sort\gsl_sort_vector.h>
#include <vector\gsl_vector.h>

#include <iostream>
#include <fstream>
#include <limits>

#include "lip.h"

#include "ddas_client_setup.h"
#include "ddas_debug.h"
#include "ddas_globals.h"

using namespace std;

/**
* @author Max Rupplin
* @date 5-15-08
* @param decimal_value The verylong decimal representation of a regression iteration
* 
* 'ddas_get_one_columns_count' returns the number of chars in a char[] that are '1' (the used columns)
*/
int ddas_get_one_columns_count(verylong decimal_value)
{
	#ifdef DEBUG_MODE
	cerr<<"ddas_get_one_columns_count called."<<endl;
	#endif

	//create a local copy of parameter value
	verylong local = 0;

	//copy parameter value to copy
	zcopy( decimal_value, &local);

	//the binary representation of 'decimal_value'
	char* binary=ddas_verylong_to_binary_char(local);

	//how many columns were used to represent 'decimal_value' in binary
	int one_column_count=0;

	//length of the representation
	int length=(int)strlen(binary);

	for(int i=0; i<length; i++)
	{
		if(binary[i]=='1')one_column_count++;
	}

	//free memory
	delete[] binary;
	zfree( &local );

	#ifdef DEBUG_MODE
	cerr<<"ddas_get_one_columns_count returning:"<< one_column_count <<endl;
	#endif
	
	return one_column_count;
}


/**
* @author Max Rupplin
* @date 5-15-08
*
* 'ddas_populate_independent_matrix' populates 'independent' variable matrix using globally scoped 'master' gsl_matrix as its data source
*/
void ddas_populate_independent_matrix()
{
	#ifdef DEBUG_MODE
	cerr<<"ddas_populate_independent_matrix called."<<endl;
	cerr<<"row_count="<<row_count<<endl;
	cerr<<"independent_var_count="<<independent_var_count<<endl;
	#endif

	//malloc then zero data
	independent=gsl_matrix_calloc(row_count, independent_var_count);

	//copy proper columns from master to dependent
	for(int i=0; i<independent_var_count; i++)
	{
		//the current column we're copying
		gsl_vector* current_column = gsl_vector_calloc(row_count);

		//copy column from 'master' into 'current_column' at index 'i' of 'master'
		gsl_matrix_get_col(current_column, master, i);

		//set column in 'independent' matrix
		gsl_matrix_set_col(independent, i, current_column);	

		//free memory
		gsl_vector_free(current_column);
	}

	#ifdef DEBUG_MODE
	cerr<<endl<<"gsl_matrix 'independent' looks like:"<<endl;
	ddas_print_gsl_matrix(independent);
	cerr<<"ddas_populate_independent_matrix returning."<<endl;
	#endif
}



/**
* @author Max Rupplin
* @date 5-15-08
* 
* 'ddas_populate_dependent_vector' populates gsl_vector 'dependent' w/ correct column from globally scoped gsl_matrix 'master'
*/
void ddas_populate_dependent_vector()
{
	#ifdef DEBUG_MODE
	cerr<<"ddas_populate_dependent_vector called."<<endl;
	#endif

	//allocate some memory
	dependent=gsl_vector_alloc(row_count);

	//copy last column of master matrix (independent_var_count) into 'dependent' vector
	gsl_matrix_get_col(dependent, master, independent_var_count);

	#ifdef DEBUG_MODE
	ddas_print_gsl_vector_v(dependent);
	cerr<<"ddas_populate_dependent_vector returning."<<endl;
	#endif
}




/**
* @author Max Rupplin
* @date 5-15-08
* @param dec The decimal version of a number
* 
* 'ddas_verylong_to_binary_char' converts a base 10 verylong to a binary representation stored in a char* 
*/
char* ddas_verylong_to_binary_char(verylong dec)
{
	#ifdef DEBUG_MODE
	cerr<<"ddas_verylong_to_binary_char called."<<endl;
	#endif

	//for modulo operations
	long two=2l;
	long one=1l;

	//create a local copy of parameter value
	verylong local = 0;

	//copy parameter value to local var
	zcopy(dec, &local);

	//binary array
	char* binary = new char[independent_var_count+1];	

	//populate binary[]
	for(int i=independent_var_count-1; i>0; i--)
	{
		if(zsmod(local, two)==one)
		{
			binary[i]='1';
		}
		else
		{
			binary[i]='0';
		}

		//local/=2
		z2div(local, &local);
	}

	//the y-intercept column is alway required
	binary[0]='1';

	//add null-termination
	binary[independent_var_count]='\0';

	//free memory
	zfree(&local);

	#ifdef DEBUG_MODE
	cerr<<"ddas_verylong_to_binary_char returning: "<<binary<<endl;
	#endif

	return binary;
}


/**
* @author Max Rupplin
* @date 5-15-08
* @param iteration The current regression iteration
* 
* Given a certain decimal iteration, return a gsl_matrix representing the used columns
*/
gsl_matrix* ddas_get_appropriate_independent_columns(verylong iteration)
{
	#ifdef DEBUG_MODE
	cerr<<"ddas_get_appropriate_independent_columns called."<<endl;
	#endif

	//keep track of which column is next
	long current_index=1;

	//the matrix to be returned
	gsl_matrix* matrix = gsl_matrix_calloc(row_count, columns_used);
	
	//for copying the columns
	gsl_vector* vector = gsl_vector_calloc(row_count);

	//allocate some memory for the char*
	char* binary=ddas_verylong_to_binary_char(iteration);

	//for each '1' column we include the binary
	for(long i=independent_var_count-1; i>0; i--)
	{
		if(binary[i]=='1')
		{
			//take column 'i' from 'master' matrix and stick it in gsl_vector 'vector'
			gsl_matrix_get_col(vector, independent, i);

			//ddas_print_gsl_vector_v(vector);

			//take 'vector' and stick it in column 'current_column' in gsl_matrix 'matrix'
			gsl_matrix_set_col(matrix, current_index, vector);	

			//increment next useable column
			current_index++;
		}
	}

	//ALWAYS store the first column (y intercept) from independent matrix
	gsl_matrix_get_col(vector, independent, 0);

	//ALWAYS store the first column (y intercept) from independent matrix
	gsl_matrix_set_col(matrix, 0, vector);	

	//free memory
	gsl_vector_free(vector);
	delete[] binary;

	#ifdef DEBUG_MODE
	cerr<<"ddas_get_appropriate_independent_columns is returning the following matrix:"<<endl;
	ddas_print_gsl_matrix(matrix);
	cerr<<"ddas_get_appropriate_independent_columns returning."<<endl;
	#endif

	//return matrix
	return matrix;
}

